package service

import (
	"crypto/md5"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"

	log "github.com/sirupsen/logrus"
)

var (
	// 定义地址、端口和 key 为常量
	serverAddress        string
	serverPort           int
	initialKey           string
	firstSendTime        time.Time
	mutex                sync.Mutex
	maxReconnectAttempts = 5
	reconnectInterval    = 2 * time.Second
	timeFile             = "first_send_time.txt" // 存储时间戳的文件
	logDirectory         = "logs"                // 存储信息的根目录
)

// 初始化配置
func init() {
	// 这里可以根据实际需要修改配置，或者从环境变量、配置文件读取
	serverAddress = "129.204.125.7"
	serverPort = 28888
	initialKey = "IkxjNNMMOO288783KOIYYT112233445556667788:::>>>???PPPOO{{AAAQ!"

	// 读取存储的时间戳（如果有）
	readFirstSendTime()
}

// 重连处理
type ReconnectHandler struct {
	bootstrap     *Bootstrap
	retryAttempts int
}

// NewReconnectHandler 创建一个新的重连处理实例
func NewReconnectHandler(bootstrap *Bootstrap) *ReconnectHandler {
	return &ReconnectHandler{
		bootstrap:     bootstrap,
		retryAttempts: maxReconnectAttempts,
	}
}

// 启动重连机制
func (handler *ReconnectHandler) run() {
	for {
		// 尝试建立 TCP 连接
		conn, err := handler.bootstrap.Dial()
		if err != nil {
			fmt.Printf("连接失败: %v\n", err)
			time.Sleep(reconnectInterval)
			continue // 如果连接失败，等待后重试
		}
		defer conn.Close()

		// 配置连接
		err = handler.bootstrap.ConfigureConnection(conn)
		if err != nil {
			fmt.Printf("配置连接失败: %v\n", err)
			continue
		}

		// 启动读取数据的 goroutine
		go handleRead(conn)

		// 设置幂等性和 12 小时时效判断
		mutex.Lock()
		defer mutex.Unlock()

		// 如果是第一次执行，或者超过了 12 小时
		if firstSendTime.IsZero() || time.Since(firstSendTime) > 12*time.Hour {
			// 发送初始化消息 "key" 给服务器
			err = sendMessage(conn, initialKey)
			if err != nil {
				fmt.Printf("发送数据出错: %v\n", err)
				return
			}

			// 更新并保存当前时间
			firstSendTime = time.Now()
			// saveFirstSendTime()

			fmt.Println("已发送初始化消息")
		} else {
			fmt.Println("已经在 12 小时内发送过消息，不重复执行。")
		}

		// 阻塞当前线程，等待连接关闭或者异常
		select {}
	}
}

// 发送消息的函数
func sendMessage(conn net.Conn, message string) error {
	_, err := conn.Write([]byte(message))
	return err
}

// 处理读取数据的逻辑
func handleRead(conn net.Conn) {
	buffer := make([]byte, 1024)
	var messageBuffer string // 临时消息缓存
	for {
		// 读取数据
		n, err := conn.Read(buffer)
		if err != nil {
			fmt.Printf("读取数据出错: %v\n", err)
			// 如果读取出错，尝试重新连接
			retryConnection()
			return
		}

		// 将接收到的数据转换为字符串
		messageBuffer += string(buffer[:n])

		// 处理所有完整的消息
		for {
			// 检查消息是否有匹配的 "[]" 包裹
			start := strings.Index(messageBuffer, "[")
			end := strings.Index(messageBuffer, "]")

			// 如果找到了一个完整的消息
			if start != -1 && end != -1 && start < end {
				// 提取消息内容
				message := messageBuffer[start+1 : end]

				// 处理收到的消息
				fmt.Printf("接收到: %s\n", message)

				// 检查是否以 "0/" 开头
				if strings.HasPrefix(message, "0/") {
					// 回复 "OK"
					err := sendMessage(conn, "OK")
					if err != nil {
						fmt.Printf("发送回复数据出错: %v\n", err)
					} else {
						fmt.Println("已回复: OK")
					}

					// 记录该信息
					err = recordMessage(message)
					if err != nil {
						fmt.Printf("记录消息出错: %v\n", err)
					} else {
						fmt.Println("信息已记录")
					}
				}

				// 从缓冲区移除已处理的消息
				messageBuffer = messageBuffer[end+1:]
			} else {
				// 如果没有完整的消息，退出循环等待更多数据
				break
			}
		}
	}
}

// 重连机制函数
func retryConnection() {
	for attempt := 1; attempt <= maxReconnectAttempts; attempt++ {
		fmt.Printf("重试连接，第 %d 次...\n", attempt)
		conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", serverAddress, serverPort))
		if err != nil {
			fmt.Printf("连接失败: %v\n", err)
			time.Sleep(reconnectInterval)
		} else {
			fmt.Println("重新连接成功！")
			// 重新启动读取数据的 goroutine
			go handleRead(conn)

			// 在每次重连后重新发送初始化消息
			err = sendMessage(conn, initialKey)
			if err != nil {
				fmt.Printf("发送初始化消息失败: %v\n", err)
			} else {
				fmt.Println("已重新发送初始化消息")
			}
			return
		}
	}
	fmt.Println("重连失败，退出程序")
	os.Exit(1)
}

// 记录符合条件的信息到文件
func recordMessage(message string) error {
	// 生成文件夹名，格式为当前日期
	dateFolder := time.Now().Format("2006-01-02")
	dirPath := fmt.Sprintf("%s-%s", logDirectory, dateFolder)

	// 如果目录不存在，则创建
	if _, err := os.Stat(dirPath); os.IsNotExist(err) {
		err := os.MkdirAll(dirPath, 0755)
		if err != nil {
			return fmt.Errorf("创建目录失败: %v", err)
		}
	}

	// 使用 MD5 生成文件名
	hash := md5.New()
	hash.Write([]byte("0/"))
	hashSum := hash.Sum(nil)
	md5String := fmt.Sprintf("%x", hashSum)

	// 检查是否已经存在该文件
	filePath := fmt.Sprintf("%s/%s.txt", dirPath, md5String)
	if _, err := os.Stat(filePath); !os.IsNotExist(err) {
		fmt.Println("该信息已存在，跳过记录")
		return nil // 文件已存在，跳过记录
	}

	// 处理接收到的消息
	go func() {
		ReviceSell(strings.TrimSpace(message))
	}()

	// 将信息写入文件
	err := ioutil.WriteFile(filePath, []byte(message), 0644)
	if err != nil {
		return fmt.Errorf("写入文件失败: %v", err)
	}

	return nil
}

// 读取并设置第一次发送时间
func readFirstSendTime() {
	// 检查文件是否存在
	if _, err := os.Stat(timeFile); err == nil {
		// 读取文件内容
		data, err := ioutil.ReadFile(timeFile)
		if err != nil {
			fmt.Println("读取文件出错:", err)
			return
		}

		// 将文件内容转换为时间戳
		timestamp, err := strconv.ParseInt(string(data), 10, 64)
		if err != nil {
			fmt.Println("解析时间戳出错:", err)
			return
		}

		// 设置 firstSendTime
		firstSendTime = time.Unix(timestamp, 0)
	} else {
		// 如果文件不存在，初始化为空
		firstSendTime = time.Time{}
	}
}

// 保存第一次发送时间到文件
func saveFirstSendTime() {
	// 将时间转换为 Unix 时间戳
	timestamp := firstSendTime.Unix()
	// 将时间戳写入文件
	err := ioutil.WriteFile(timeFile, []byte(strconv.FormatInt(timestamp, 10)), 0644)
	if err != nil {
		fmt.Printf("保存时间戳失败: %v\n", err)
	}
}

// Bootstrap 用于配置和管理 TCP 连接
type Bootstrap struct {
	serverAddress string // 服务器地址
	serverPort    int    // 端口
}

// NewBootstrap 创建一个新的 Bootstrap 实例
func NewBootstrap(address string, port int) *Bootstrap {
	return &Bootstrap{
		serverAddress: address,
		serverPort:    port,
	}
}

// Dial 尝试建立连接
func (b *Bootstrap) Dial() (net.Conn, error) {
	address := fmt.Sprintf("%s:%d", b.serverAddress, b.serverPort)
	conn, err := net.DialTimeout("tcp", address, 30*time.Second)
	return conn, err
}

// ConfigureConnection 设置连接的其他参数（例如保持连接活跃等）
func (b *Bootstrap) ConfigureConnection(conn net.Conn) error {
	// 将连接转换为 TCP 连接
	tcpConn, ok := conn.(*net.TCPConn)
	if !ok {
		return fmt.Errorf("无法将连接转换为 *net.TCPConn")
	}

	// 配置 TCP 连接选项
	err := tcpConn.SetKeepAlive(true)
	if err != nil {
		return fmt.Errorf("设置保持活动失败: %v", err)
	}

	// 设置 Keep-Alive 时间为 60 秒
	tcpConn.SetKeepAlivePeriod(60 * time.Second)

	// 设置读写缓冲区大小
	tcpConn.SetReadBuffer(1024 * 64)
	tcpConn.SetWriteBuffer(1024 * 64)

	return nil
}

func RunNetty() {
	log.Info("机器人跑起来~")

	time.Sleep(time.Second * 5)

	// 随机操作
	go func() {
		for {
			buySellDTO := BuySellDTO{
				Type: 3,
			}
			handle(buySellDTO)
			time.Sleep(time.Minute * 30)
		}
	}()

	// // 模拟买入
	go func() {
		// for {
		buySellDTO := BuySellDTO{
			Type:    0,
			StockNo: "600225",
			Price:   2.45,
			Count:   100,
		}
		handle(buySellDTO)
		time.Sleep(time.Second * 10)
		// }
	}()
	// 创建 Bootstrap 实例
	bootstrap := NewBootstrap(serverAddress, serverPort)

	// 创建重连处理器并启动
	handler := NewReconnectHandler(bootstrap)
	handler.run()
}
